package lumis.service.portalmanagement.xsleditor;

import java.io.IOException;
import java.net.URL;
import java.util.EnumSet;

import lumis.doui.processaction.ProcessActionHandler;
import lumis.doui.source.Source;
import lumis.portal.PortalException;
import lumis.portal.UnexpectedException;
import lumis.portal.cluster.IClusterCommand;
import lumis.portal.cluster.IClusterManager;
import lumis.portal.cluster.IClusterTransmission.Flag;
import lumis.portal.filesystem.PortalBaseFolder;
import lumis.portal.filesystem.PortalFile;
import lumis.portal.filesystem.PortalFilePath;
import lumis.portal.manager.ManagerFactory;
import lumis.portal.manager.ManagerFactoryInternal;
import lumis.portal.service.ServiceConfig;
import lumis.portal.serviceinterface.IServiceInterfaceManager;
import lumis.portal.serviceinterface.style.ServiceInterfaceStyleConfig;
import lumis.portal.serviceinterfaceinstance.IServiceInterfaceInstanceManager;
import lumis.portal.serviceinterfaceinstance.ServiceInterfaceInstanceConfig;
import lumis.util.PortalUtil;
import lumis.util.TextUtil;
import lumis.util.XmlUtil;

/**
 * Process action handler responsible for handling operations on XSL files.
 * 
 * @version $Revision: 12710 $ $Date: 2011-03-18 17:00:16 -0300 (Fri, 18 Mar 2011) $
 * @since 4.0.0
 */
public class XslEditorProcessActionHandler extends ProcessActionHandler<Source>
{
	public static final String STYLE_ADD = "lum_xslAdd";
	public static final String STYLE_UPDATE_INFO = "lum_xslUpdateInfo";
	public static final String STYLE_SAVE_FILE = "lum_xslSaveFile";
	public static final String STYLE_APPLY = "lum_xslApply";
	public static final String STYLE_DELETE = "lum_xslDelete";
	public static final String STYLE_CLEAR_CACHE = "lum_xslClearCache"; 
	
	public static final String COPY_FROM_BLANK_STYLE = "BLANK_STYLE";
	public static final String COPY_FROM_STYLE_IN_EDITION = "STYLE_IN_EDITION";
	
	public void processAction() throws PortalException
	{
		String actionType = XmlUtil.readAttributeString("actionType", processActionNode);
		
		if(actionType.equals(STYLE_ADD))
			processAddAction();
		else if(actionType.equals(STYLE_UPDATE_INFO))
			processUpdateInfo();
		else if(actionType.equals(STYLE_SAVE_FILE))
			processSaveFile();
		else if(actionType.equals(STYLE_APPLY))
			processApply();
		else if(actionType.equals(STYLE_DELETE))
			processDelete();
		else if(actionType.equals(STYLE_CLEAR_CACHE))
			clearFileCache();
	}

	protected void processDelete() throws PortalException
	{
		try
		{
			IServiceInterfaceManager serviceInterfaceManager = ManagerFactory.getServiceInterfaceManager();

			String serviceInterfaceStyleId = getParameter("interfaceStyleId", String.class);
			String serviceInterfaceId = getParameter("callerInterfaceId", String.class);
			ServiceInterfaceStyleConfig style = serviceInterfaceManager.getStyle(sessionConfig, serviceInterfaceStyleId, serviceInterfaceId, transaction);
			
			// TODO: Ariel crate a resource file for xsl editor, include the below string and use this resource file here.
			if(style.isFromDefinition())
				throw new PortalException("STR_CANNOT_DELETE_INTERFACE_DEFAULT_STYLES", douiContext.getRequest().getServiceConfig().getResource());
			String xslFilePath = style.getFilePath();
			
			serviceInterfaceManager.deleteStyle(sessionConfig, serviceInterfaceStyleId, serviceInterfaceId, transaction);
			
			PortalFile xslFile = new PortalFile(new PortalFilePath(PortalBaseFolder.DEF, xslFilePath));
			xslFile.delete();
			
			addDefaultResponse();
		}
		catch (PortalException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			throw new UnexpectedException(e);
		}
	}

	protected void processAddAction() throws PortalException
	{
		String serviceInterfaceId = getParameter("interfaceId", String.class);
		String serviceInterfaceStyleId = PortalUtil.generateNewGuid();
		String name = getParameter("name", String.class);
		String description = getParameter("description", String.class);
		String filePath = getParameter("filePath", String.class);
		String xslContent = getParameter("xslContent", String.class);
		String copyFrom = getParameter("copyFrom", String.class);
		String xslEditorInterfaceInstanceId = getParameter("xslEditorInterfaceInstanceId", String.class);
		Boolean createFile = (Boolean) getParameter("createFile");
		
		if(createFile == null)
			createFile = Boolean.TRUE;
		
		if(filePath.indexOf("../") != -1 || filePath.indexOf("..\\") != -1)
		{
			throw new PortalException("STR_INVALID_PATH", douiContext.getRequest().getServiceConfig().getResource());
		}
		
		if(!filePath.toUpperCase().endsWith(".XSL"))
			filePath = filePath + ".xsl";
		PortalFile xslFile = new PortalFile(new PortalFilePath(PortalBaseFolder.DEF, filePath));
		
		// if the specified file already exists, request overwrite confirmation from user
		if (xslFile.exists() && createFile.booleanValue())
		{
			throw new PortalException("STR_FILE_ALREADY_EXISTS", douiContext.getRequest().getServiceConfig().getResource());
		}
		
		if (!xslFile.exists() && !createFile.booleanValue())
		{
			throw new PortalException("STR_FILE_NOT_FOUND", douiContext.getRequest().getServiceConfig().getResource());
		}
		
		try
		{
			// create the new style based on the style currently in edition
			// (possibly unsaved)
			if (copyFrom.equals(COPY_FROM_STYLE_IN_EDITION) && createFile.booleanValue())
			{
				// save the xsl content to the new file, remove Revision comments
				saveXslFile(xslContent, xslFile);
			}
			else if(copyFrom.equals(COPY_FROM_BLANK_STYLE) && createFile.booleanValue())
			{
		
				ServiceConfig serviceConfig = douiContext.getRequest().getServiceConfig();
				xslContent = TextUtil.read(ManagerFactory.getDeploymentManager().getClassLoader().getResource("lumis/service/portalmanagement/xsleditor/style/blank.xsl"), "UTF-8");
				String styleCodeHereMessage = ManagerFactory.getLocalizationManager().localize("STR_STYLE_CODE_HERE", serviceConfig.getResource());
				xslContent = TextUtil.stringReplace(xslContent, "Style Code Here", styleCodeHereMessage);
				String encoding = XmlUtil.getXmlEncoding(xslContent);
				
				// save the xsl content to the new file
				ManagerFactory.getFileSystemManager().writeFile(xslFile, xslContent.getBytes(encoding));				
			}
			else if(createFile.booleanValue())
			{
				IServiceInterfaceManager serviceInterfaceManager = ManagerFactory.getServiceInterfaceManager();
				ServiceInterfaceStyleConfig serviceInterfaceStyleConfig = serviceInterfaceManager.getStyle(sessionConfig, copyFrom, serviceInterfaceId, transaction);

				// remove Revision comments
				// save the xsl content to the new file, remove Revision comments
				URL xslURL = ManagerFactory.getDeploymentManager().getClassLoader().getResource(serviceInterfaceStyleConfig.getFilePath());
				if (xslURL == null)
					throw new IllegalArgumentException("Cannot find " + serviceInterfaceStyleConfig.getFilePath());
				String sourceFileXslContent = TextUtil.read(xslURL, "UTF-8");
				saveXslFile(sourceFileXslContent, xslFile);
			}
			
		}
		catch (Exception e)
		{
			throw new PortalException("STR_ERROR_SAVING_FILE;"+filePath, douiContext.getRequest().getServiceConfig().getResource(), e);
		}
		
		IServiceInterfaceManager serviceInterfaceManager = ManagerFactory.getServiceInterfaceManager();
		ServiceInterfaceStyleConfig serviceInterfaceStyleConfig = new ServiceInterfaceStyleConfig();

		serviceInterfaceStyleConfig.setId(serviceInterfaceStyleId);
		serviceInterfaceStyleConfig.setServiceInterfaceId(serviceInterfaceId);
		serviceInterfaceStyleConfig.setName(name);
		serviceInterfaceStyleConfig.setDescription(description);
		serviceInterfaceStyleConfig.setFilePath(filePath);

		serviceInterfaceManager.addOrUpdateStyle(sessionConfig, serviceInterfaceStyleConfig, transaction);

		String script =  "if(window.opener != null){var interfaceStyleIdSelect = window.opener.document.getElementById('interfaceStyleId');var newOptionAdd = window.opener.document.createElement('OPTION');" +
				"newOptionAdd.selected = true; newOptionAdd.value = '"+serviceInterfaceStyleId+"'; newOptionAdd.innerText = '"+name+"';interfaceStyleIdSelect.appendChild(newOptionAdd);};  " +
				"window.opener.document.forms['Form_"+xslEditorInterfaceInstanceId+"'].elements['doui_renderAction'].value='none'; window.opener.LumisPortal.onSubmitForm('Form_"+xslEditorInterfaceInstanceId+"','"+xslEditorInterfaceInstanceId+"',null,false,null,null);";
		
		addResponseParameter(ProcessActionHandler.RESPONSE_TYPE_RUN_JAVASCRIPT, script);
		addDefaultResponse();
	}

	/**
	 * Saves a XSL file. Revision comment is removed from xslContent before saving. 
	 * @param xslContent the XSL file content.
	 * @param xslFile the destination file.
	 * @since 4.2.0
	 */
	private void saveXslFile(String xslContent, PortalFile xslFile) throws IOException 
	{
		xslContent = xslContent.replaceAll("(<!-- ).*(\\$Revision:).*\\$.*(-->)", "");
		String encoding = XmlUtil.getXmlEncoding(xslContent);
		if(encoding == null)
			encoding = "UTF-8";
		ManagerFactory.getFileSystemManager().writeFile(xslFile, xslContent.getBytes(encoding));
	}
	
	private void processApply() throws PortalException
	{
		Boolean isDirty = getParameter("isXslDirty", Boolean.class);
		if(isDirty != null && isDirty.booleanValue())
			saveFile();
		
		// TODO make sure that the current user has access to create service
		// update the instance
		String interfaceInstanceId = getParameter("callerInterfaceInstanceId", String.class);
		String interfaceStyleId = getParameter("interfaceStyleId", String.class);

		// get the interface instance current info
		IServiceInterfaceInstanceManager serviceInterfaceInstanceManager = ManagerFactory.getServiceInterfaceInstanceManager();
		ServiceInterfaceInstanceConfig serviceInterfaceInstanceConfig = serviceInterfaceInstanceManager.get(sessionConfig, interfaceInstanceId, transaction);

		// update interface instance info
		serviceInterfaceInstanceConfig.setServiceInterfaceStyleId(interfaceStyleId);
		serviceInterfaceInstanceManager.update(sessionConfig, serviceInterfaceInstanceConfig, transaction);

		addDefaultResponse();
	}

	private void processSaveFile() throws PortalException
	{
		try
		{
			saveFile();
			addDefaultResponse();
		}
		catch (PortalException e)
		{
			throw e;
		}
		catch (Exception e)
		{ 	
			throw new UnexpectedException(e);
		}
	}
	
	private void saveFile() throws PortalException
	{
		try
		{
			// TODO make sure that the current user has access to this operation
			// TODO After Kishnan copy processActionNode into dataNode,
			// determite sourceId and pass it will not me necessary anymore
			String xslContent = getParameter("data", String.class);
			String filePath = getParameter("filePath", String.class);
			
			if(xslContent == null)
				xslContent = "";
			
			PortalFile xslFile = new PortalFile(new PortalFilePath(PortalBaseFolder.DEF, filePath));
			XslFileSaveCommand saveRunnable = new XslFileSaveCommand(xslFile, xslContent);
			
			IClusterManager clusterManager = ManagerFactory.getClusterManager();
			IClusterCommand saveCommand = clusterManager.createClusterCommand(saveRunnable);
			saveCommand.getFlags().addAll(EnumSet.of(Flag.DURABLE, Flag.TOTAL_ORDER));
			
			clusterManager.send(saveCommand);
		}
		catch (PortalException e)
		{
			throw e;
		}
		catch (Exception e)
		{ 	
			throw new UnexpectedException(e);
		}
	}
	
	private void processUpdateInfo() throws PortalException
	{
		String serviceInterfaceId = getParameter("interfaceId", String.class);
		String serviceInterfaceStyleId = getParameter("interfaceStyleId", String.class);
		String name = getParameter("name", String.class);
		String description = getParameter("description", String.class);
		
		IServiceInterfaceManager serviceInterfaceManager = ManagerFactory.getServiceInterfaceManager();
		ServiceInterfaceStyleConfig serviceInterfaceStyleConfig = serviceInterfaceManager.getStyle(sessionConfig, serviceInterfaceStyleId, serviceInterfaceId, transaction);
		
		serviceInterfaceStyleConfig.setName(name);
		serviceInterfaceStyleConfig.setDescription(description);
		
		serviceInterfaceManager.addOrUpdateStyle(sessionConfig, serviceInterfaceStyleConfig, transaction);

		addDefaultResponse();
	}
	
	private void clearFileCache() throws PortalException
	{
		String filePath = getParameter("filePath", String.class);
		ManagerFactoryInternal.getXslCacheManager().clearXslCache(douiContext.getRequest().getSessionConfig(), filePath, transaction);
		addDefaultResponse();
	}
	
}
